﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using tom;
using System.Runtime.InteropServices;
using System.Threading;
using System.Text.RegularExpressions;
using System.Drawing;

namespace IrcChatClient.SpecificControls
{
    public class RichEditorCsharp : RichTextBox
    {



        private Thread th = null;
        public RichEditorCsharp()
        {

        }
        #region WIN32
        [DllImport("User32.dll")]
        public static extern int SendMessage(IntPtr hWnd, int message, IntPtr wParam, out IntPtr lParam);
        private const int EM_GETOLEINTERFACE = WM_USER + 60;
        public const int WM_USER = 0x0400;
        #endregion

        #region TOM OBJECT MODEL
        private ITextDocument _myITextDocument = null;
        private ITextDocument myITextDocument
        {
            get
            {
                if (_myITextDocument == null)
                    _myITextDocument = Create();
                return _myITextDocument;
            }
            set
            {
                if (_myITextDocument != null)
                    Marshal.ReleaseComObject(_myITextDocument);
                _myITextDocument = value;
            }
        }
        private ITextDocument Create()
        {
            IntPtr theRichEditOle = IntPtr.Zero;
            if (SendMessage(Handle, EM_GETOLEINTERFACE, IntPtr.Zero, out theRichEditOle) == 0)
            {
                throw new System.ComponentModel.Win32Exception();
            }
            try
            {
                ITextDocument theTextDoc = (ITextDocument)Marshal.GetTypedObjectForIUnknown(theRichEditOle, typeof(ITextDocument));
                return theTextDoc;
            }
            finally
            {
                Marshal.Release(theRichEditOle);
            }
        }
        private void FreezeDocument(ITextDocument doc)
        {
            doc.Freeze();
        }
        private void UnFreezeDocument(ITextDocument doc)
        {
            doc.Unfreeze();
        }
        private Boolean setForeColor(int start, int len, System.Drawing.Color backcolor)
        {
            Boolean ret = false;
            ITextRange range = myITextDocument.Range(start, start + len);
            FreezeDocument(myITextDocument);
            range.Font.ForeColor = System.Drawing.ColorTranslator.ToOle(backcolor);
            UnFreezeDocument(myITextDocument);
            return ret;
        }
        #endregion
        #region DELEGATE
        private delegate Boolean Updatecolor(int start, int len, System.Drawing.Color backcolor);
        #endregion

        #region KEYWORD C#
        static String[] Word = new String[] {
    "abstract","as","base","bool","break","byte","case","catch","char","checked","class","const","continue","decimal",
    "default","delegate","do","double","else","enum","event","exdouble","exfloat","explicit","extern","false","finally","fixed",
    "float","for","foreach","get","goto","if","implicit","in","int","interface","internal","is","lock","long","namespace",
    "new","null","object","operator","out","override","private","protected","public","readonly","ref","return","sbyte","sealed",
    "set","short","sizeof","static","string","struct","switch","this","throw","true","try","typeof","uint","ulong","unchecked",
    "unsafe","ushort","using","virtual","void"
    };

        

        static readonly Regex regString = new Regex("(@\"|\")[^\"]*(?:\\\\.[^\"]*)*\"", RegexOptions.Multiline | RegexOptions.Compiled);
        static readonly Regex regCommentSingle = new Regex("[^:]//[^\r\n]*", RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.ExplicitCapture);
        static readonly Regex regCommentMultiple = new Regex("/\\*([^*]|(\\*+([^*/])))*\\*+/", RegexOptions.Multiline | RegexOptions.Compiled);
        static Regex regKeywords = new Regex(CompileKeywords(), RegexOptions.Singleline | RegexOptions.Compiled);
        /// <summary>
        /// gerene un motif de regex
        /// </summary>
        /// <returns></returns>
        static private string CompileKeywords()
        {
            string mKeywords = "";
            for (int i = 0; i < Word.Length; i++)
            {
                string strKeyword = Word[i];
                if (i == Word.Length - 1)
                    mKeywords += "\\b" + Word[i] + "\\b";
                else
                    mKeywords += "\\b" + Word[i] + "\\b|";
            }
            return mKeywords;
        }

        public void setWord(String[] dWord)
        {
            Word = dWord;
            Console.WriteLine("essais"+Word[0]);
            Regex regString = new Regex("(@\"|\")[^\"]*(?:\\\\.[^\"]*)*\"", RegexOptions.Multiline | RegexOptions.Compiled);
            Regex regCommentSingle = new Regex("[^:]//[^\r\n]*", RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.ExplicitCapture);
            Regex regCommentMultiple = new Regex("/\\*([^*]|(\\*+([^*/])))*\\*+/", RegexOptions.Multiline | RegexOptions.Compiled);
            regKeywords = new Regex(CompileKeywords(), RegexOptions.Singleline | RegexOptions.Compiled);
        }

        #endregion
        /// <summary>
        /// Mise a jour inter-Thread
        /// </summary>
        /// <param name="start">debut de mot</param>
        /// <param name="len">fin de mot</param>
        /// <param name="color">couleur désiré</param>
        private void UpdateContent(int start, int len, Color color)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new Updatecolor(setForeColor), new Object[] { start, len, color });
            }
            else
                setForeColor(start, len, color);
        }
        /// <summary>
        /// Color le text
        /// </summary>
        /// <param name="data">Text de la richtextbox</param>
        public void ColorSystaxe(object data)
        {
            String Text = data as String;
            Match regMatch;

            UpdateContent(0, Text.Length, Color.Black);

            /* color mot clé */
            for (regMatch = regKeywords.Match(Text); regMatch.Success; regMatch = regMatch.NextMatch())
            {
                int nStart = regMatch.Index;
                int nLenght = regMatch.Length;
                UpdateContent(nStart, nLenght, Color.Blue);
            }


            /* color string avec ou sans @*/
            for (regMatch = regString.Match(Text); regMatch.Success; regMatch = regMatch.NextMatch())
            {
                int nStart = regMatch.Index;
                int nLenght = regMatch.Length;
                UpdateContent(nStart, nLenght, Color.Red);
            }

            /* color commentaire // */
            for (regMatch = regCommentSingle.Match(Text); regMatch.Success; regMatch = regMatch.NextMatch())
            {

                int nStart = regMatch.Index;
                int nLenght = regMatch.Length;
                UpdateContent(nStart, nLenght, Color.Green);
            }

            /* color commentaire multiligne */
            for (regMatch = regCommentMultiple.Match(Text); regMatch.Success; regMatch = regMatch.NextMatch())
            {
                int nStart = regMatch.Index;
                int nLenght = regMatch.Length;
                UpdateContent(nStart, nLenght, Color.Green);
            }
        }

        protected override void OnHandleCreated(EventArgs e)
        {
            base.OnHandleCreated(e);
            ColorSystaxe(Text);
        }
        protected override void OnTextChanged(EventArgs e)
        {
            base.OnTextChanged(e);
            /*
            * arrete le traitement si l'analise est dejas en cours
            */
            if (th != null && th.IsAlive)
                return;
            /*
            * lance l'analyse dans un thread
            */
            th = new Thread(new ParameterizedThreadStart(ColorSystaxe));
            th.IsBackground = true;
            th.Start(Text);
        }

        private void InitializeComponent()
        {
            this.SuspendLayout();
            this.ResumeLayout(false);

        }
    }
}

